
#include <iostream>

using std::cout;
using std::endl;

class Base
{
public:
    Base(long base): _base(base) 
    {  cout << "Base(long)" << endl;    }

    virtual
    void print() const
    {   cout << "_base:" << _base << endl;}

    virtual
    void display() const
    {   cout << "Base::display()" << endl;}

private:
    long _base;
};

class Derived1
: public Base
{
public:
    //virtual   编译报错
    Derived1(long base, long derived)
    : Base(base)
    , _derived(derived)
    {   cout << "Derived1(long,long)" << endl;}


    //当基类的同名函数设置为虚函数之后，
    //在派生类中重定义了该函数,即使前面没有加上virtual
    //该函数依然是虚函数
    //virtual
    void print() const  override
    {   cout << "Derived1::_derived:" << _derived << endl;    }

    virtual void show() const
    {   cout << "Derived1::show()" << endl;    }

private:
    long _derived;
};

//基于基类Base扩展一个新的派生类
class Derived2
: public Base
{
public:
    Derived2(long base, long derived)
    : Base(base)
    , _derived(derived)
    {   cout << "Derived2(long,long)" << endl;}


    //当基类的同名函数设置为虚函数之后，
    //在派生类中重定义了该函数,即使前面没有加上virtual
    //该函数依然是虚函数
    //可以在形参列表之后，大括号之前加上override关键字
    //表示要覆盖基类虚函数
    void print() const //override
    {   
        cout << "Derived2::_derived:" << _derived << endl;    
        cout << "Derived2::_data:" << _data << endl;
    }

private:
    long _derived;
    long _data;
};


//采用虚函数的优势：
//当需求发生变化时，可以很方便的扩展代码
//而不需要对原先的代码进行修改
//
//(Open-Closed Principle)
//面向对象设计原则中有一条：对扩展开放，对修改关闭
void display(Base * pbase)
{
    //只看编译时，应该要调用的是基类的print函数
    pbase->print();
}

//动态多态被激活的条件：
//1. 基类要定义虚函数
//2. 派生类要重定义(覆盖)虚函数
//3. 创建派生类对象
//4. 基类指针指向派生类对象
//5. 通过基类指针调用虚函数

//虚函数如何实现的？
//1. 当类中定义了一个虚函数时，该类所创建的对象之中
//会多一个虚函数指针
//2. 虚函数指针指向了一张虚函数表
//3. 虚函数表中存放的是虚函数的入口地址

int main()
{
    cout << "sizeof(Base): " << sizeof(Base) << endl;
    cout << "sizeof(Derived1): " << sizeof(Derived1) << endl;
    Base base(1);
    Derived1 d1(10, 100);
    Derived2 d2(20, 200);

    display(&base);//Base * pbase = &base;
    display(&d1);//Base * pbase = &d1;
    display(&d2);//Base * pbase = &d2;


    return 0;
}

